#include "SystemClass.h"
#include "_MyDebug_.h"
SystemClass::SystemClass()
{
	m_Input = 0;
	m_Graphics = 0;
}

SystemClass::SystemClass(const SystemClass &other)
{

}

SystemClass::~SystemClass()
{
}

bool SystemClass::Initialize()
{
	int screenWidth, screenHeight;
	bool result;

	screenWidth = 0;
	screenHeight = 0;
	// init window
	InitializeWindows(screenWidth, screenHeight);

	// init input obj
	m_Input = new InputClass();
	if(!m_Input)
	{
		return false;
	}
	m_Input->Initialize();

	// init graphics obj
	m_Graphics = new GraphicsClass();
	if(!m_Graphics)
	{
		return false;
	}
	result = m_Graphics->Initialize(screenWidth, screenHeight, m_hwnd);
	if(!result)
	{
		return false;
	}

	return true;
}

void SystemClass::Run()
{
	MSG msg;
	bool done, result;

	// init the message structure
	ZeroMemory(&msg, sizeof(MSG));

	// loop until there is a quit message from window or user
	done = false;
	while(!done)
	{
		// handle the window messages
		if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}

		// if window singals to end the app then exit out
		if(msg.message == WM_QUIT)
		{
			done = true;
		}
		else
		{
			// otherwise do the frame processing
			result = Frame();
			if(!result)
			{
				done = true;
			}
		}
	}
	return;
}

void SystemClass::Shutdown()
{
	// release graphics obj
	if(m_Graphics)
	{
		m_Graphics->ShutDown();
		SAFE_DEL(m_Graphics);
	}

	// release input obj
	SAFE_DEL(m_Input);

	// shutdown window
	ShutdownWindows();

	return;
}

bool SystemClass::Frame()
{
	bool result;
	// check if user pressed escape & want to exit the app
	if(m_Input->IsKeyDown(VK_ESCAPE))
	{
		return false;
	}

	// do the frame processing for the graphics obj
	result = m_Graphics->Frame();
	if(!result)
	{
		return false;
	}

	return true;
}

LRESULT CALLBACK SystemClass::MessageHandler(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam)
{
	switch(umsg)
	{
	case WM_KEYDOWN:
		m_Input->KeyDown((unsigned int)wParam);
		return 0;
		break;
	case WM_KEYUP:
		m_Input->KeyUp((unsigned int)wParam);
		return 0;
		break;
	default:
		return DefWindowProc(hwnd, umsg, wParam, lParam);		
	}
}

void SystemClass::InitializeWindows(int& screenWidth, int& screenHeight)
{
	WNDCLASSEX wc;
	DEVMODE dmScreenSettings;
	int posX, posY;

	// get an external pointer to this obj
	ApplicationHandler = this;

	// get the instance of this app
	m_hInstance = GetModuleHandle(NULL);

	// give app a name
	m_applicationName = L"Engine Direct 11";

	// set up the window class with default setting
	wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;	
	wc.lpfnWndProc = WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = m_hInstance;
	wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
	wc.hIconSm = wc.hIcon;
	wc.hCursor = LoadCursor(NULL,IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);	
	wc.lpszMenuName = NULL;
	wc.lpszClassName = m_applicationName;
	wc.cbSize = sizeof(WNDCLASSEX);

	// register window class
	RegisterClassEx(&wc);

	// determine resolution of desktop creen
	screenWidth = GetSystemMetrics(SM_CXSCREEN);
	screenHeight = GetSystemMetrics(SM_CYSCREEN);

	// set up the screen settings depending on whether it is running in full screen or in window mode
	if (FULL_SCREEN)
	{
		//if full screen set the screen to max size of the desktop & 32 bit
		memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
		dmScreenSettings.dmSize = sizeof(dmScreenSettings);
		dmScreenSettings.dmPelsWidth = (unsigned long) screenWidth;
		dmScreenSettings.dmPelsHeight = (unsigned long) screenHeight;
		dmScreenSettings.dmBitsPerPel = 32;
		dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

		// change the display setting to full screen
		ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);

		// set the position of window to the top left corner
		posX = posY = 0;
	}
	else
	{
		// if windowed then set it to 800x600
		screenWidth = 800;
		screenHeight = 600;

		// place the window in the middle of screen
		posX = (GetSystemMetrics(SM_CXSCREEN) - screenWidth)/2;
		posY = (GetSystemMetrics(SM_CYSCREEN) - screenHeight)/2;
	}

	// create the window with the screen settings and get the handle to it
	m_hwnd = CreateWindowEx(
		WS_EX_APPWINDOW,
		m_applicationName,
		m_applicationName,
		WS_OVERLAPPEDWINDOW,//WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP,
		posX, posY, screenWidth, screenHeight, 
		NULL, NULL, m_hInstance, NULL);

	// bring the window up on the screen and set it as main focus
	ShowWindow(m_hwnd, SW_SHOW);
	SetForegroundWindow(m_hwnd);
	SetFocus(m_hwnd);

	// hide the mouse cursor
	ShowCursor(true);

}

void SystemClass::ShutdownWindows()
{
	// show mouse cursor
	ShowCursor(true);

	// fix the display setting if leaving full screen mode
	if(FULL_SCREEN)
	{
		ChangeDisplaySettings(NULL, 0);
	}
	
	// remove the window
	DestroyWindow(m_hwnd);
	m_hwnd = NULL;

	// remove the app instance
	UnregisterClass(m_applicationName, m_hInstance);
	m_hInstance = NULL;

	// release the pointer to this class
	ApplicationHandler = NULL;
	return;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam)
{
	switch(umsg)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
		break;
	case WM_CLOSE:
		PostQuitMessage(0);
		return 0;
		break;
	// all other msg pass to the message handler in system class
	default:
		{
		return ApplicationHandler->MessageHandler(hwnd, umsg, wParam, lParam);	
		}
	}
}
